/**
 * WebRTC SDK - 点对点视频通话SDK
 * 基于原生WebRTC API封装，支持信令服务器连接、P2P连接、媒体流管理
 */
class WebRTCSDK {
  constructor(options = {}) {
    // 默认配置
    this.config = {
      // 信令服务器配置
      signalingServer: options.signalingServer || 'wss://polaris.uat.yixincapital.com/aio-webrtc/',
      
      // ICE服务器配置
      iceServers: options.iceServers || [
        { urls: 'stun:stun.l.google.com:19302' },
        { urls: 'stun:stun1.l.google.com:19302' },
        { urls: 'stun:stun2.l.google.com:19302' },
        { urls: 'stun:stun3.l.google.com:19302' },
        { urls: 'stun:stun4.l.google.com:19302' },
        // { urls: 'stun:47.101.40.207:3478'},
        // { urls: 'turn:47.101.40.207:3478', username: 'turn', credential: 'turntest' },
        // { urls: 'turn:47.101.40.207:3478?transport=tcp', username: 'turn', credential: 'turntest' },
        // { urls: 'turns:47.101.40.207:5349?transport=tcp', username: 'turn', credential: 'turntest' }
        { urls: 'stun:123.103.73.215:3478'},
        { urls: 'turn:123.103.73.215:3478', username: 'turn', credential: 'turntest' },
        { urls: 'turn:123.103.73.215:3478?transport=tcp', username: 'turn', credential: 'turntest' },
        { urls: 'turns:123.103.73.215:3478?transport=tcp', username: 'turn', credential: 'turntest' } 
      ],
      cameraVidpid: '1bcf:28c4',
      audioVidpid: '5448:1522',
      
      // 媒体约束
      mediaConstraints: {
        video: options.video !== false ? {
          width: { ideal: 1280 },
          height: { ideal: 720 },
        } : false,
        audio: options.audio !== false ? {
          // 启用原生音频处理
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true,
          // 音频采样率优化
          sampleRate: 48000,
          sampleSize: 16,
          // 声道配置
          channelCount: 1,
          // 延迟优化
          latency: 0.01,
          // 音量控制
          volume: 0.7,
          // 音频编解码器偏好
          googEchoCancellation: true,
          googAutoGainControl: true,
          googNoiseSuppression: true,
          googHighpassFilter: true,
          googTypingNoiseDetection: true,
          googAudioMirroring: false
        } : false
      },
      
      // 调试模式
      debug: options.debug || false,
      
      // 自动重连
      autoReconnect: options.autoReconnect !== false,
      
      // 重连间隔（毫秒）
      reconnectInterval: options.reconnectInterval || 3000,
      
      // 最大重连次数
      maxReconnectAttempts: options.maxReconnectAttempts || 5
    }

    // 状态管理
    this.state = {
      connected: false,
      inCall: false,
      localStream: null,
      peers: new Map(), // uid -> { pc, stream, settings }
      peerList: [],
      currentUserId: null,
      currentRoomId: null,
      loginMessgae: null
    }

    // WebSocket连接
    this.ws = null
    this.reconnectAttempts = 0
    this.reconnectTimer = null
    this.heartbeatTimer = null
    this.lastPongAt = 0

    // 事件系统
    this.events = new Map()

    // 绑定方法
    this._bindMethods()
  }

  /**
   * 绑定方法到实例
   */
  _bindMethods() {
    this.on = this.on.bind(this)
    this.off = this.off.bind(this)
    this.emit = this.emit.bind(this)
    this._handleMessage = this._handleMessage.bind(this)
    this._handleConnectionClose = this._handleConnectionClose.bind(this)
    this._handleConnectionError = this._handleConnectionError.bind(this)
  }

  /**
   * 事件监听
   */
  on(event, callback) {
    if (!this.events.has(event)) {
      this.events.set(event, [])
    }
    this.events.get(event).push(callback)
  }

  /**
   * 移除事件监听
   */
  off(event, callback) {
    if (!this.events.has(event)) return
    const callbacks = this.events.get(event)
    const index = callbacks.indexOf(callback)
    if (index > -1) {
      callbacks.splice(index, 1)
    }
  }

  /**
   * 触发事件
   */
  emit(event, ...args) {
    if (!this.events.has(event)) return
    this.events.get(event).forEach(callback => {
      try {
        callback(...args)
      } catch (error) {
        console.error(`Error in event callback for ${event}:`, error)
      }
    })
  }

  /**
   * 连接信令服务器
   */
  async connect(message, deviceId = '', roomId = '') {
    const userId = deviceId

    if (this.state.connected) {
      throw new Error('Already connected to signaling server')
    }

    if (!deviceId || !roomId) {
      this.emit('error', { type: 'connectError', error: '房间ID或设备ID不存在' })
      return
    }

    this.state.currentUserId = userId
    this.state.currentRoomId = roomId
    this.state.loginMessgae = message

    return new Promise((resolve, reject) => {
      try {
        this.ws = new WebSocket(`${this.config.signalingServer}?uid=${userId}&roomId=${roomId}`)
        
        this.ws.onopen = () => {
          this.state.connected = true
          this.reconnectAttempts = 0
          // 启动应用层心跳（备用）：每 25 秒发送一条 ping 文本
          this._startHeartbeat()
          
          // 发送登录消息
          this._send({
            cmd: 'cmd_login',
            uid: userId,
            roomId: roomId,
            msg: message
          })
          
          this.emit('connected')
          resolve()
        }

        this.ws.onmessage = (event) => {
          // 处理心跳 pong
          try {
            const message = JSON.parse(event.data)
            if (message.cmd === 'cmd_pong') {
              this.lastPongAt = Date.now()
              return
            }
          } catch (e) { /** */ }
          this._handleMessage(event)
        }
        this.ws.onclose = this._handleConnectionClose
        this.ws.onerror = this._handleConnectionError

        // 连接超时
        setTimeout(() => {
          if (!this.state.connected) {
            reject(new Error('Connection timeout'))
          }
        }, 10000)

      } catch (error) {
        reject(error)
      }
    })
  }

  /**
   * 断开连接
   */
  disconnect() {
    this._cleanup()
    this.emit('disconnected')
  }

  async _findCamera() {
    try {
      const res = await navigator.mediaDevices.enumerateDevices()

      const cameras = res.filter((device) => device.kind === 'videoinput')
      const cur_camera = cameras.find((device) => {
        console.log('[WebRtcSdk] camera ---', device.label)
        return device.label.toLowerCase().includes(this.config.cameraVidpid)
      })
      console.log('[WebRtcSdk] _findCamera find camera: ', this.config.cameraVidpid,  cur_camera != null) 
      return cur_camera?.deviceId
    } catch (err) {
      console.log('[WebRtcSdk] initCamera find camera error:')
      console.log(err) 
      return null
    }
  }
  
  async _findAudio() {
    try {
      const res = await navigator.mediaDevices.enumerateDevices()
  
      const cameras = res.filter((device) => device.kind === 'audioinput')
      const cur_audio = cameras.find((device) => {
        console.log('[WebRtcSdk] audio ---', device.label)
        // 阵列式麦克风包含多个usb设备, 查找专门用于通话的麦克风设备(硬件降噪)
        return device.label.toLowerCase().includes(this.config.audioVidpid) && device.deviceId == 'communications' 
      })
      console.log('[WebRtcSdk] _findAudio find : ', this.config.audioVidpid,  cur_audio != null) 
      return cur_audio?.deviceId
    } catch (err) {
      console.log('[WebRtcSdk] _findAudio find camera error:')
      console.log(err) 
      return null
    }
  }


  /**
   * 开始通话
   */
  async startCall(msg) {
    if (!this.state.connected) {
      throw new Error('Not connected to signaling server')
    }

    if (this.state.inCall) {
      throw new Error('Already in call')
    }

    try {
      // 发送开始通话消息
      this._send({
        cmd: 'cmd_start_call',
        uid: this.state.currentUserId,
        roomId: this.state.currentRoomId,
        msg
      })

      this.state.inCall = true
      this.emit('callWait')
      
    } catch (error) {
      this.emit('error', { type: 'startCall', error })
      throw error
    }
  }

  // 接受通话
  async _incomingCall() {
    if (!this.state.connected) {
      throw new Error('Not connected to signaling server')
    }
    
    try {
      // 获取本地媒体流
      await this._getLocalStream()

      this._send({
        cmd: 'cmd_join_room',
        uid: this.state.currentUserId,
        roomId: this.state.currentRoomId
      })

      this.emit('callStarted')
    } catch (error) {
      this.emit('error', { type: '_incomingCall', error })
      throw error
    }
  }

  /**
   * 结束通话
   */
  endCall() {
    if (!this.state.inCall) return

    // 清理所有P2P连接
    this._cleanupPeers()
    
    // 停止本地媒体流
    if (this.state.localStream) {
      this.state.localStream.getTracks().forEach(track => track.stop())
      this.state.localStream = null
    }

    // 发送挂断消息
    this._send({
      cmd: 'cmd_hang_up',
      uid: this.state.currentUserId,
      roomId: this.state.currentRoomId
    })

    this.state.inCall = false
    this.emit('callEnded')
  }

  /**
   * 切换麦克风状态
   */
  toggleMicrophone() {
    if (!this.state.localStream) return false

    const audioTracks = this.state.localStream.getAudioTracks()
    if (audioTracks.length === 0) return false

    const enabled = !audioTracks[0].enabled
    audioTracks[0].enabled = enabled

    // 广播音视频状态
    this._broadcastAVStatus()

    this.emit('microphoneToggled', enabled)
    return enabled
  }

  /**
   * 切换摄像头状态
   */
  toggleCamera() {
    if (!this.state.localStream) return false

    const videoTracks = this.state.localStream.getVideoTracks()
    if (videoTracks.length === 0) return false

    const enabled = !videoTracks[0].enabled
    videoTracks[0].enabled = enabled

    // 广播音视频状态
    this._broadcastAVStatus()

    this.emit('cameraToggled', enabled)
    return enabled
  }

  /**
   * 获取本地媒体流
   */
  async _getLocalStream() {
    try {
      // 使用优化的音频约束
      let optimizedConstraints = this._getOptimizedMediaConstraints()

      // 获取设备
      const cameraDevId = await this._findCamera()
      console.log('[WebRtcSdk] cameraDevId :', cameraDevId)
      if (cameraDevId) {
        optimizedConstraints.video.deviceId = {
          exact: cameraDevId
        }
      }
      
      const audioDevId = await this._findAudio() 
      console.log('[WebRtcSdk] audioDevId :', audioDevId)
      if (audioDevId) {
        optimizedConstraints.audio.deviceId = {
          exact: audioDevId
        }
      }
      
      
      try {
        this.state.localStream = await navigator.mediaDevices.getUserMedia(optimizedConstraints)
      } catch (error) {
        optimizedConstraints.video = false
        this.state.localStream = await navigator.mediaDevices.getUserMedia(optimizedConstraints)
      }

      // 应用音频优化
//      if (typeof window !== 'undefined' && window.audioOptimizer) {
//        await window.audioOptimizer.optimizeAudioStream(this.state.localStream)
//      }

      // 额外的音频处理优化
      this._optimizeAudioStream(this.state.localStream);
      
      this.emit('localStream', this.state.localStream)
      return this.state.localStream
    } catch (error) {
      this.emit('error', { type: 'getUserMedia', error })
      throw error
    }
  }

  /**
   * 获取优化的媒体约束
   */
  _getOptimizedMediaConstraints() {
    // 检测平台并应用相应的音频优化
    // const userAgent = navigator.userAgent.toLowerCase()
    // const isAndroid = userAgent.includes('android')
    // const isIOS = userAgent.includes('iphone') || userAgent.includes('ipad')
    // const isWindows = userAgent.includes('windows')
    // const isMac = userAgent.includes('mac')

    let audioConstraints = this.config.mediaConstraints.audio

    // if (audioConstraints && typeof audioConstraints === 'object') {
    //   // 根据平台调整音频约束
    //   if (isAndroid) {
    //     // 安卓设备优化
    //     audioConstraints = {
    //       ...audioConstraints,
    //       sampleRate: 44100,
    //       channelCount: 1,
    //       latency: 0.02,
    //       googNoiseSuppression2: true,
    //       googEchoCancellation2: true,
    //       googDAEchoCancellation: true
    //     }
    //   } else if (isWindows) {
    //     // Windows设备优化
    //     audioConstraints = {
    //       ...audioConstraints,
    //       sampleRate: 48000,
    //       channelCount: 2,
    //       latency: 0.01,
    //       googNoiseSuppression2: true,
    //       googEchoCancellation2: true,
    //       googDAEchoCancellation: true,
    //       googAutoGainControl2: true
    //     }
    //   } else if (isIOS) {
    //     // iOS设备优化
    //     audioConstraints = {
    //       ...audioConstraints,
    //       sampleRate: 48000,
    //       channelCount: 1,
    //       latency: 0.01
    //     }
    //   } else if (isMac) {
    //     // Mac设备优化
    //     audioConstraints = {
    //       ...audioConstraints,
    //       sampleRate: 48000,
    //       channelCount: 2,
    //       latency: 0.01
    //     }
    //   }
    // }

    return {
      ...this.config.mediaConstraints,
      audio: {
        ...audioConstraints,
        sampleRate: 48000,
        channelCount: 1,
        latency: 0.01,
        googNoiseSuppression2: true,
        googEchoCancellation2: true,
        googDAEchoCancellation: true,
        googAutoGainControl2: true
      }
    }
  }

  /**
   * 获取优化的ICE配置
   */
  _getOptimizedIceConfig() {
    // const userAgent = navigator.userAgent.toLowerCase()
    // const isAndroid = userAgent.includes('android')
    // const isMobile = isAndroid || userAgent.includes('iphone') || userAgent.includes('ipad')

    // 基础ICE配置
    let iceConfig = {
      iceServers: this.config.iceServers,
      iceTransportPolicy: 'all',
      iceCandidatePoolSize: 5,
      bundlePolicy: 'max-bundle',
      rtcpMuxPolicy: 'require',
      //encodedInsertableStreams: true
    }

    // 移动设备优化
  //  if (isMobile) {
  //    iceConfig = {
  //      ...iceConfig,
  //      iceTransportPolicy: 'all',
  //      iceCandidatePoolSize: 5, // 减少候选池大小以节省资源
  //      bundlePolicy: 'max-bundle',
  //      rtcpMuxPolicy: 'require'
  //    }
  //  } else {
  //    // PC设备优化
  //    iceConfig = {
  //      ...iceConfig,
  //      iceTransportPolicy: 'all',
  //      iceCandidatePoolSize: 10,
  //      bundlePolicy: 'max-bundle',
  //      rtcpMuxPolicy: 'require'
  //    }
  //  }

    return iceConfig
  }

  /**
   * 创建P2P连接
   */
  _createPeerConnection(uid) {
    if (this.state.peers.has(uid)) {
      return this.state.peers.get(uid)
    }

    // 获取优化的ICE服务器配置
    const iceConfig = this._getOptimizedIceConfig()
    
    const pc = new RTCPeerConnection(iceConfig)

    const peer = {
      pc,
      stream: null,
      settings: {
        mic: true,
        cam: true,
        mirror: false
      }
    }

    // 添加本地流到连接
    if (this.state.localStream) {
      this.state.localStream.getTracks().forEach(track => {
        pc.addTrack(track, this.state.localStream)
      })
    }

    // 监听远程流
    pc.ontrack = (event) => {
      const stream = event.streams[0] || event.stream
      if (stream) {
        peer.stream = stream
        this.emit('remoteStream', { uid, stream })
      }
    }

    // 监听ICE候选
    pc.onicecandidate = (event) => {
      if (event.candidate) {
        this._send({
          cmd: 'cmd_ice',
          roomId: this.state.currentRoomId,
          uid: this.state.currentUserId,
          remoteUid: uid,
          msg: {
            sdpMid: event.candidate.sdpMid,
            sdpMLineIndex: event.candidate.sdpMLineIndex,
            sdp: event.candidate.candidate
          }
        })
      }
    }

    // 监听连接状态变化
    pc.oniceconnectionstatechange = () => {
      if (pc.iceConnectionState === 'connected') {
        this.emit('peerConnected', { uid })
      } else if (pc.iceConnectionState === 'failed') {
        this.emit('peerConnectionFailed', { uid })
      }
    }

    pc.onconnectionstatechange = () => {
      this._log(`Connection state for ${uid}: ${pc.connectionState}`)
    }

    this.state.peers.set(uid, peer)
    return peer
  }

  /**
   * 发起offer
   */
  async _createOffer(uid) {
    // 兜底：若尚未获取本地媒体，先获取
    if (!this.state.localStream) {
      try { await this._incomingCall() } catch (e) { return }
    }

    const peer = this._createPeerConnection(uid)
    
    try {
      const offer = await peer.pc.createOffer()
      await peer.pc.setLocalDescription(offer)

      this._send({
        cmd: 'cmd_offer',
        roomId: this.state.currentRoomId,
        uid: this.state.currentUserId,
        remoteUid: uid,
        msg: offer.sdp
      })

      // 发送音视频状态
      this._send({
        cmd: 'cmd_av_status',
        roomId: this.state.currentRoomId,
        uid: this.state.currentUserId,
        remoteUid: uid,
        msg: {
          is_share: false,
          mic: this._isMicrophoneEnabled(),
          cam: this._isCameraEnabled(),
          mirror: false
        }
      })

    } catch (error) {
      this.emit('error', { type: 'createOffer', error, uid })
      throw error
    }
  }

  /**
   * 处理offer
   */
  async _handleOffer(from, sdp) {
    const peer = this._createPeerConnection(from)
    
    try {
      await peer.pc.setRemoteDescription({
        type: 'offer',
        sdp: sdp
      })

      const answer = await peer.pc.createAnswer()
      await peer.pc.setLocalDescription(answer)

      this._send({
        cmd: 'cmd_answer',
        roomId: this.state.currentRoomId,
        uid: this.state.currentUserId,
        remoteUid: from,
        msg: answer.sdp
      })

      // 发送音视频状态
      this._send({
        cmd: 'cmd_av_status',
        roomId: this.state.currentRoomId,
        uid: this.state.currentUserId,
        remoteUid: from,
        msg: {
          is_share: false,
          mic: this._isMicrophoneEnabled(),
          cam: this._isCameraEnabled(),
          mirror: false
        }
      })

    } catch (error) {
      this.emit('error', { type: 'handleOffer', error, from })
      throw error
    }
  }

  /**
   * 处理answer
   */
  async _handleAnswer(from, sdp) {
    const peer = this.state.peers.get(from)
    if (!peer) return

    try {
      await peer.pc.setRemoteDescription({
        type: 'answer',
        sdp: sdp
      })
    } catch (error) {
      this.emit('error', { type: 'handleAnswer', error, from })
      throw error
    }
  }

  /**
   * 处理ICE候选
   */
  async _handleIceCandidate(from, candidate) {
    const peer = this.state.peers.get(from)
    if (!peer) return

    try {
      await peer.pc.addIceCandidate(new RTCIceCandidate({
        sdpMid: candidate.sdpMid,
        sdpMLineIndex: candidate.sdpMLineIndex,
        candidate: candidate.sdp
      }))
    } catch (error) {
      this.emit('error', { type: 'handleIceCandidate', error, from })
    }
  }

  /**
   * 处理信令消息
   */
  _handleMessage(event) {
    try {
      const message = JSON.parse(event.data)
      switch (message.cmd) {
        case 'cmd_current_peers':
          this.state.peerList = message.msg.peerList || []
          this.emit('peerListUpdated', this.state.peerList, message.msg)
          break

        case 'cmd_peer_join':
          this.state.peerList.push(message.msg.uid)
          this.emit('peerJoined', message.msg.uid, message.msg)
          break

        case 'cmd_start_call':
          this.emit('startCall', message.msg)
          break

        case 'cmd_new_peer':
          this._createOffer(message.uid)
          break

        case 'cmd_offer':
          this._handleOffer(message.uid, message.msg)
          break

        case 'cmd_answer':
          this._handleAnswer(message.uid, message.msg)
          break

        case 'cmd_ice':
          this._handleIceCandidate(message.uid, message.msg)
          break

        case 'cmd_peer_leave':
          this._removePeer(message.msg.peerId)
          break

        case 'cmd_av_status':
          this._updatePeerSettings(message.uid, message.msg)
          break

        case 'cmd_hang_up':
          this.state.inCall = false

          // 清理所有P2P连接
          this._cleanupPeers()
          
          // 停止本地媒体流
          if (this.state.localStream) {
            this.state.localStream.getTracks().forEach(track => track.stop())
            this.state.localStream = null
          }
          this.emit('callEnded')
          break
        case 'cmd_error':
          this.emit('error', message.msg)
          break
        default:
          this._log('Unknown message command:', message.cmd)
      }
    } catch (error) {
      this.emit('error', { type: 'handleMessage', error })
    }
  }

  /**
   * 移除对等连接
   */
  _removePeer(uid) {
    const peer = this.state.peers.get(uid)
    if (peer) {
      peer.pc.close()
      this.state.peers.delete(uid)
      
      const index = this.state.peerList.indexOf(uid)
      if (index > -1) {
        this.state.peerList.splice(index, 1)
      }
    }

    const index1 = this.state.peerList.indexOf(uid);
    if (index1 > -1) {
      this.state.peerList.splice(index1, 1);
    }

    this.emit('peerLeft', uid)
  }

  /**
   * 更新对等方设置
   */
  _updatePeerSettings(uid, settings) {
    const peer = this.state.peers.get(uid)
    if (peer) {
      Object.assign(peer.settings, settings)
      this.emit('peerSettingsUpdated', { uid, settings })
    }
  }

  /**
   * 广播音视频状态
   */
  _broadcastAVStatus() {
    this._send({
      cmd: 'cmd_av_status',
      roomId: this.state.currentRoomId,
      uid: this.state.currentUserId,
      msg: {
        is_share: false,
        mic: this._isMicrophoneEnabled(),
        cam: this._isCameraEnabled(),
        mirror: false
      }
    })
  }

  /**
   * 检查麦克风是否启用
   */
  _isMicrophoneEnabled() {
    if (!this.state.localStream) return false
    const audioTracks = this.state.localStream.getAudioTracks()
    return audioTracks.length > 0 && audioTracks[0].enabled
  }

  /**
   * 检查摄像头是否启用
   */
  _isCameraEnabled() {
    if (!this.state.localStream) return false
    const videoTracks = this.state.localStream.getVideoTracks()
    return videoTracks.length > 0 && videoTracks[0].enabled
  }

  /**
   * 发送信令消息
   */
  _send(message) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(message))
    } else {
      this.emit('error', { type: 'sendMessage', error: 'WebSocket not connected' })
    }
  }

  /**
   * 处理连接关闭
   */
  _handleConnectionClose() {
    this.state.connected = false
    this.emit('disconnected')
    this._stopHeartbeat()

    // 自动重连
    if (this.config.autoReconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {
      this._scheduleReconnect()
    }
  }

  /**
   * 处理连接错误
   */
  _handleConnectionError(error) {
    this.emit('error', { type: 'connection', error })
  }

  /**
   * 安排重连
   */
  _scheduleReconnect() {
    this.reconnectAttempts++
    
    this.reconnectTimer = setTimeout(() => {
      this.connect(this.state.loginMessgae, this.state.currentUserId, this.state.currentRoomId)
        .catch(error => {
          this.emit('error', { type: 'reconnect', error })
        })
    }, this.config.reconnectInterval)
  }

  /**
   * 清理资源
   */
  _cleanup() {
    // 清理重连定时器
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer)
      this.reconnectTimer = null
    }

    // 清理P2P连接
    this._cleanupPeers()

    // 停止本地媒体流
    if (this.state.localStream) {
      this.state.localStream.getTracks().forEach(track => track.stop())
      this.state.localStream = null
    }

    // 关闭WebSocket连接
    if (this.ws) {
      this.ws.close()
      this.ws = null
    }

    // 停止心跳
    this._stopHeartbeat()

    // 重置状态
    this.state.connected = false
    this.state.inCall = false
    this.state.peerList = []
    this.reconnectAttempts = 0
  }

  /**
   * 清理P2P连接
   */
  _cleanupPeers() {
    this.state.peers.forEach(peer => {
      peer.pc.close()
    })
    this.state.peers.clear()
  }

  /**
   * 日志输出
   */
  _log(...args) {
    if (this.config.debug) {
      console.log('[WebRTCSDK]', ...args)
    }
  }

  // ------- 心跳机制（应用层） -------
  _startHeartbeat() {
    this._stopHeartbeat()
    const HEARTBEAT_INTERVAL_MS = 25000
    this.lastPongAt = Date.now()
    this.heartbeatTimer = setInterval(() => {
      if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return
      try {
        // 发送文本 ping；服务端若未特殊处理，将忽略，不影响
        this.ws.send(JSON.stringify({ cmd: 'cmd_ping' }))
      } catch (e) { /** */ }
      // 30 秒未收到 pong，主动关闭触发重连
      if (Date.now() - this.lastPongAt > 30000) {
        try { this.ws.close() } catch (e) { /** */ }
      }
    }, HEARTBEAT_INTERVAL_MS)
  }

  _stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer)
      this.heartbeatTimer = null
    }
  }

  /**
   * 获取当前状态
   */
  getState() {
    return {
      connected: this.state.connected,
      inCall: this.state.inCall,
      peerList: [...this.state.peerList],
      localStream: this.state.localStream,
      peers: Array.from(this.state.peers.keys())
    }
  }

  /**
   * 获取对等方设置
   */
  getPeerSettings(uid) {
    const peer = this.state.peers.get(uid)
    return peer ? { ...peer.settings } : null
  }

  _optimizeAudioStream(stream) {
    const audioTracks = stream.getAudioTracks()
    if(audioTracks.length > 0) {
      const audioTrack = audioTracks[0];
      const settings = audioTrack.getSettings();
      
      // 设置合适的音量级别
      if(settings.volume !== undefined) {
        audioTrack.applyConstraints({ volume: 0.7 });
      }
      
      // 启用舒适噪音生成
      if(settings.echoCancellation !== undefined) {
        audioTrack.applyConstraints({ 
          echoCancellation: true,
          noiseSuppression: true 
        });
      }
    }
	}
}

// 导出SDK
if (typeof module !== 'undefined' && module.exports) {
  module.exports = WebRTCSDK
} else if (typeof window !== 'undefined') {
  window.WebRTCSDK = WebRTCSDK
}
